package com.learn.yh.aws;

import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.secretsmanager.AWSSecretsManager;
import com.amazonaws.services.secretsmanager.AWSSecretsManagerClientBuilder;
import com.amazonaws.services.secretsmanager.model.*;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.config.YamlMapFactoryBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.web.context.support.StandardServletEnvironment;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class AwsSecretJdbcEnvironmentPostProcessor implements EnvironmentPostProcessor {
    public static final String SECRET_PROPERTIES = "AwsPropertySource";
    public static final String SECRET_CONFIG = "classpath:/META-INF/AwsSecret.yml";
    private static final ObjectMapper objectMapper = new ObjectMapper();

    static {//忽略位置属性
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    /**
     * get AwsSecret info map
     */
    public Map<String, AwsSecret> getSecret(AwsSecretProperties awsPropertySource) throws IOException {
        Map<String, AwsSecret> target = new HashMap<>();
        AwsSecretProperties.Property[] aws = awsPropertySource.getAws();
        if (aws == null) {
            return Collections.emptyMap();
        }
        for (AwsSecretProperties.Property aw : aws) {
            AwsSecret secret = getSecret(aw);
            for (String replacePrefix : aw.getReplacePrefixes()) {
                target.put(replacePrefix, secret);
            }
        }
        return target;
    }

    /**
     * get AwsSecret with Yaml file
     * this is a http request
     */
    public AwsSecret getSecret(AwsSecretProperties.Property aws) throws IOException {
        String secretName = aws.getSecretName();
        String endpoint = aws.getEndpoint();
        String region = aws.getRegion();
        AwsClientBuilder.EndpointConfiguration config = new AwsClientBuilder.EndpointConfiguration(endpoint, region);
        AWSSecretsManagerClientBuilder clientBuilder = AWSSecretsManagerClientBuilder.standard();
        clientBuilder.setEndpointConfiguration(config);
        YamlCredentialsProvider yamlCredentialsProvider = YamlCredentialsProvider.of(aws);
        clientBuilder.withCredentials(yamlCredentialsProvider);
        AWSSecretsManager client = clientBuilder.build();
        String secret;
        ByteBuffer binarySecretData;
        GetSecretValueRequest getSecretValueRequest = new GetSecretValueRequest()
                .withSecretId(secretName)
                .withVersionStage("AWSCURRENT");
        GetSecretValueResult getSecretValueResult = null;
        try {
            getSecretValueResult = client.getSecretValue(getSecretValueRequest);
        } catch (ResourceNotFoundException e) {
            System.err.println("The requested secret " + secretName + " was not found" + e.getMessage());
        } catch (InvalidRequestException | InvalidParameterException e) {
            System.err.println("The request was invalid due to: " + e.getMessage());
        }
        if (getSecretValueResult == null) {
            return null;
        }
        //获取aws存储的信息转为Bean对象
        if (getSecretValueResult.getSecretString() != null) {
            secret = getSecretValueResult.getSecretString();
            return objectMapper.readValue(secret, AwsSecret.class);
        } else {
            binarySecretData = getSecretValueResult.getSecretBinary();
            return objectMapper.readValue(binarySecretData.toString(), AwsSecret.class);
        }
    }

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        MutablePropertySources propertySources = environment.getPropertySources();
        if (!(environment instanceof StandardServletEnvironment)) {
            return;
        }
        loadAwsPropertySource(application, propertySources);
    }

    /**
     * StandardServletEnvironment add AwsPropertySource
     * we addFirst make username and password can't Override
     */
    private void loadAwsPropertySource(SpringApplication application, MutablePropertySources propertySources) {
        if (propertySources.contains(SECRET_PROPERTIES)) {
            return;
        }
        try {
            AwsSecretProperties load = load(application.getResourceLoader() == null ? new DefaultResourceLoader() : application.getResourceLoader());
            AwsPropertySource awsPropertySource = AwsPropertySource.of(SECRET_PROPERTIES, getSecret(load));
            propertySources.addFirst(awsPropertySource);
        } catch (Exception e) {
            System.err.println("Get SecretValue error " + e.getMessage());
        }
    }

    /**
     * get Local Yaml file
     */

    private AwsSecretProperties load(ResourceLoader resourceLoader) throws IOException {
        Resource resource = resourceLoader.getResource(SECRET_CONFIG);
        YamlMapFactoryBean yamlMapFactoryBean = new YamlMapFactoryBean();
        yamlMapFactoryBean.setResources(resource);
        Map<String, Object> object = yamlMapFactoryBean.getObject();
        return objectMapper.readValue(objectMapper.writeValueAsString(object), AwsSecretProperties.class);
    }
}
